#region Using Statements
using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
#endregion

namespace Xfinity.Rendering
{
    public delegate void TextureUpdateDelegate<T>(GameTime gameTime, T[] destinationArary) where T : struct;
    /// <summary>
    /// This is a game component that implements IUpdateable.
    /// </summary>
    public class ProceduralTexture<T> : DrawableGameComponent where T : struct
    {
        #region Texture
        private Texture2D texture;

        /// <summary>
        /// Texture.
        /// </summary>
        public Texture2D Texture
        {
            get { return texture; }
        }

        #endregion
        #region Width
        private int width;

        /// <summary>
        /// Width.
        /// </summary>
        public int Width
        {
            get { return width; }
        }

        #endregion
        #region Height
        private int height;

        /// <summary>
        /// Height.
        /// </summary>
        public int Height
        {
            get { return height; }
        }

        #endregion
        #region SurfaceFormat
        private SurfaceFormat surfaceFormat;

        /// <summary>
        /// SurfaceFormat.
        /// </summary>
        public SurfaceFormat SurfaceFormat
        {
            get { return surfaceFormat; }
        }

        #endregion
        #region TextureUpdateDelegate
        private TextureUpdateDelegate<T> updateDelegate;

        /// <summary>
        /// UpdateDelegate.
        /// </summary>
        public TextureUpdateDelegate<T> UpdateDelegate
        {
            get { return updateDelegate; }

        }

        #endregion

        public ProceduralTexture(TextureUpdateDelegate<T> updateDelegate, int width, int height, SurfaceFormat surfaceFormat,Game game)
            : base(game)
        {
            this.width = width;
            this.height = height;
            this.surfaceFormat = surfaceFormat;
            this.updateDelegate = updateDelegate;
            this.dataArray = new T[width * height];
        }


        /// <summary>
        /// Allows the game component to perform any initialization it needs to before starting
        /// to run.  This is where it can query for any required services and load content.
        /// </summary>
        public override void Initialize()
        {
            // TODO: Add your initialization code here

            base.Initialize();
        }
        protected override void LoadGraphicsContent(bool loadAllContent)
        {
            throw new NotImplementedException();
         //   texture = new Texture2D(GraphicsDevice, width, height, 0, ResourceUsage.ResolveTarget | ResourceUsage.AutoGenerateMipMap, surfaceFormat);
            base.LoadGraphicsContent(loadAllContent);
        }
        T[] dataArray;
        /// <summary>
        /// Allows the game component to update itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        public override void Update(GameTime gameTime)
        {
            // TODO: Add your update code here
            updateDelegate(gameTime, dataArray);
            texture.SetData<T>(dataArray);
            base.Update(gameTime);
        }
        public static implicit operator Texture2D(ProceduralTexture<T> texture)
        {
            return texture.texture;
        }
    }
}


